﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Krile.Kernel;
using Krile.Kernel.Control;
using Krile.Kernel.Control.Surface;
using Krile.Kernel.Control.Surface.MessageObjects;
using Krile.Common;
using System.Net;
using System.Text.RegularExpressions;

namespace Twinkle.Common
{
    public static class XStringGenerator
    {
        public static XString CreateXString(this string text, string replyToId, Tweak.TStatus.StatusKinds kind)
        {
            XString xs = new Krile.Kernel.Control.XString();
            xs.Original = text;
            if (!String.IsNullOrEmpty(replyToId))
            {
                if (kind == Tweak.TStatus.StatusKinds.DirectMessage)
                    xs.HeaderText = "d @" + replyToId;
                else
                    xs.HeaderText = "@" + replyToId;
            }
            if (kind == Tweak.TStatus.StatusKinds.Retweet)
            {
                text = text.Substring(3);
                xs.HeaderText = "[RT]";
            }
            xs.MessageObjects = CreateMsgObjects(text, kind == Tweak.TStatus.StatusKinds.Retweet);
            return xs;
        }

        public static Regex AtRegexEx = new Regex(@"@([A-Za-z0-9_]*(?:/[A-Za-z0-9_]*)?)", RegexOptions.Singleline | RegexOptions.Compiled); 
        public static Regex HashRegex = new Regex("(?<![A-Za-z0-9])(#[A-Za-z0-9_]+)", RegexOptions.Compiled | RegexOptions.Singleline);
        static MessageObject[] CreateMsgObjects(string msg, bool retweet)
        {
            msg = msg.Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;").Replace("\r", "").Replace("\n", " ");
            //pre-processor
            msg = Krile.Common.Regexs.URLRegex.Replace(msg,
                new MatchEvaluator((m) =>
                    {
                        if (m.Captures.Count > 0)
                        {
                            return "<" + m.Captures[0].Value.Replace("#", "&sharp;") + ">" + m.Captures[0].Value.Replace("#", "&sharp;") + "<";
                        }
                        else
                            return m.Value;
                    }));
           
            msg = AtRegexEx.Replace(msg, "@<" + "http://twitter.com/" + "$1>$1<");
            msg = HashRegex.Replace(msg,
                new MatchEvaluator((m) =>
                    {
                        if (m.Captures.Count > 0)
                        {
                            Kernel.Storage.AddHashtag(m.Captures[0].Value);
                            return "<http://twitter.com/search?q=" + Uri.EscapeDataString(m.Captures[0].Value) + ">" + m.Captures[0].Value + "<";
                        }
                        else
                            return m.Value;
                    }));
            List<MessageObject> objStock = new List<MessageObject>();
            if (retweet)
            {
                objStock.Add(new Controls.RTLabel());
                objStock.Add(new Text(" "));
            }
            foreach (var item in msg.Split(new[] { '<' }, StringSplitOptions.RemoveEmptyEntries))
            {
                if (item.Contains('>'))
                {
                    var iArray = item.Split('>');
                    //link
                    string origstr = iArray[0].Replace("&lt;", "<").Replace("&gt;", ">").Replace("&amp;", "&");
                    if (origstr.StartsWith("http://twitter.com/"))
                    {
                        objStock.Add(new Hyperlink(origstr, iArray[1].Replace("&lt;", "<").Replace("&gt;", ">").Replace("&amp;", "&")));
                    }
                    else
                    {
                        origstr = origstr.Replace("&lt;", "<").Replace("&gt;", ">").Replace("&sharp;","#").Replace("&amp;", "&");
                        if (Kernel.Config.External.URLShoteningService.AutoResolveURL)
                        {
                            string newstr = null;
                            foreach (var dcp in URLShortener.URLShortenManager.GetDecompressors())
                            {
                                if (dcp.TryDecompress(origstr, out newstr))
                                {
                                    origstr = newstr;
                                    break;
                                }
                            }
                        }
                        objStock.Add(new Hyperlink(origstr));
                        Image ig = null;
                        if (Kernel.Config.External.ImageEmbeddingService.ExtractEmbedded && (ig = GetImage(origstr)) != null)
                        {
                            objStock.Add(ig);
                        }
                    }
                    continue;
                }
                else
                    objStock.Add(new Text(item.Replace("&lt;", "<").Replace("&gt;", ">").Replace("&amp;", "&")));
            }
            return objStock.ToArray();
        }

        private static Image GetImage(string url)
        {
            //twitpic twitgoo hatenaFotolife keitaiHyakkei img.ly
            //and png jpg bmp gif
            if (url.StartsWith("http://twitpic.com/"))
            {
                //twitpic
                try
                {
                    var sub = url.Substring(19);
                    return new Image(new Uri("http://twitpic.com/show/large/" + sub));
                }
                catch
                {
                    return null;
                }
            }
            else if (url.StartsWith("http://pckles.com/") || url.StartsWith("http://pckl.es/"))
            {
                try
                {
                    return new Image(new Uri(url + ".png"));
                }
                catch
                {
                    return null;
                }
            }
            else if (url.StartsWith("http://twitgoo.com/"))
            {
                //twitgoo
                //twitpic
                try
                {
                    var sub = url.Substring(19);
                    return new Image(new Uri("http://twitgoo.com/show/img/" + sub));
                }
                catch
                {
                    return null;
                }

            }
            else if (url.StartsWith("http://img.ly/"))
            {
                //img.ly
                try
                {
                    var sub = url.Substring(14);
                    return new Image(new Uri("http://img.ly/show/large/" + sub));
                }
                catch
                {
                    return null;
                }
            }
            else if (url.StartsWith("http://movapic.com/"))
            {
                //keitai hyakkei
                var nc = new NetConnect();
                try
                {
                    var ret = nc.WebConnectDownloadString(new Uri(url), "GET", null);
                    if (ret.Succeeded)
                    {
                        var pos = ret.Data.IndexOf("http://image.movapic.com/pic/m_", StringComparison.Ordinal);
                        if (pos == -1) return null;
                        var urlcontains = ret.Data.Substring(pos);
                        pos = urlcontains.IndexOf("\"", StringComparison.Ordinal);
                        if (pos <= 0) return null;
                        urlcontains = urlcontains.Substring(0, pos);
                        return new Image(new Uri(urlcontains));
                    }
                    else
                        return null;
                }
                catch
                {
                    return null;
                }
            }
            else if (url.StartsWith("http://f.hatena.ne.jp/"))
            {
                //hatena fotolife
                //http://f.hatena.ne.jp/userid/YYYYMMDDhhmmss
                //http://img.f.hatena.ne.jp/images/fotolife/u[userid[0]]/userid/YYYYMMDD/YYYYMMDDhhmmss.(jpg|png)
                var splits = url.Split(new[] { '/' });
                if (splits.Length == 5)
                {
                    long val;
                    if (long.TryParse(splits[4], out val))
                    {
                        //callback url is:
                        var un = splits[3];
                        var id = splits[4];
                        if(String.IsNullOrEmpty(un) || String.IsNullOrEmpty(id) || id.Length != 14)
                            return null;
                        var callback = "http://img.f.hatena.ne.jp/images/fotolife/" + un[0] + "/" + un + "/" + id.Substring(0, 8) + "/" + id + ".jpg";
                        var callback2 = "http://img.f.hatena.ne.jp/images/fotolife/" + un[0] + "/" + un + "/" + id.Substring(0, 8) + "/" + id + ".png";
                        try
                        {
                            try
                            {
                                if ((int)GetStatusCode(callback) < 400)
                                {
                                    return new Image(new Uri(callback));
                                }
                            }
                            catch { }
                            return new Image(new Uri(callback2));
                        }
                        catch (UriFormatException)
                        {
                            return null;
                        }
                    }
                }
            }
            else if (url.EndsWith(".png") ||
                url.EndsWith(".jpg") || url.EndsWith(".jpeg") || url.EndsWith(".jpe") ||
                url.EndsWith(".bmp") || url.EndsWith(".dib") ||
                url.EndsWith("gif"))
            {
                try
                {
                    return new Image(new Uri(url));
                }
                catch (UriFormatException)
                {
                    return null;
                }
            }
            return null;
        }

        static public HttpStatusCode GetStatusCode(string url)
        {

            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
            HttpWebResponse res = null;
            HttpStatusCode statusCode;

            try
            {
                res = (HttpWebResponse)req.GetResponse();
                statusCode = res.StatusCode;

            }
            catch (WebException ex)
            {

                res = (HttpWebResponse)ex.Response;

                if (res != null)
                {
                    statusCode = res.StatusCode;
                }
                else
                {
                    throw; // サーバ接続不可などの場合は再スロー
                }
            }
            finally
            {
                if (res != null)
                {
                    res.Close();
                }
            }
            return statusCode;
        }
    }
}
